package cn.demoncat.util.websocket.base;

import cn.demoncat.util.web.constant.AppConstant;
import cn.demoncat.util.websocket.entity.UserSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.websocket.*;

/**
 * WS服务端点
 *
 * 1、每个websocket连接会初始化一个WsServer，持有独立的session
 * 
 * 2、客户端每次打开连接（刷新页面、重新连接、多标签页），都会创建新的会话
 * 
 * @author 延晓磊
 *
 * @since 2018年3月29日
 */
//@ServerEndpoint(value = "/ws")
//@Component
public abstract class BaseWsServer {

	/**
	 * 客户端Session
	 * 
	 * 每一个连接创建一个Bean，持有独立的Session（同于方法的参数Session）
	 */
	private UserSession session;
	
	/**
	 * 获取WS Service BeanName
	 *
	 * 说明：WS中无法注入Bean，需要通过ApplicationContext获取
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年5月18日
	 */
	protected abstract String getServiceName();

	/**
	 * 在客户端初次连接时触发
	 * 
	 * @param session
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年8月30日
	 */
	@OnOpen
	public void onOpen(Session session) {
		// 客户端连接
		this.session = new UserSession(session);
		this.getLogger().info("WebSocket - 客户端创建连接：session = {}, user = {}, token = {}", session.getId(), this.session.getUserId(), this.session.getCtoken());
		// 业务处理
		this.getService().onOpen(this.session);
	}

	/**
	 * 在客户端断开连接时触发
	 * 
	 * @param session
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年8月30日
	 */
	@OnClose
	public void onClose(Session session) {
		// 客户端断开
		this.getLogger().info("WebSocket - 客户端断开连接：session = {}, user = {}, token = {}", session.getId(), this.session.getUserId(), this.session.getCtoken());
		// 业务处理
		this.getService().onClose(this.session);
	}

	/**
	 * 收到客户端消息后
	 * 
	 * @param session
	 * @param message	消息
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年8月30日
	 */
	@OnMessage
	public void onMessage(Session session, String message) {
		// 收到消息
		this.getLogger().debug("WebSocket - 客户端发送消息：session = {}, user = {}, token = {}, message = {}", session.getId(), this.session.getUserId(), this.session.getCtoken(), message);
		// 业务处理
		this.getService().onMessage(this.session,message);
	}

	/**
	 * 发生错误时（会关闭连接，即执行onClose）
	 * 
	 * @param session
	 * @param error
	 * 
	 * @author 延晓磊
	 *
	 * @since 2018年8月30日
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		// 连接出错
		this.getLogger().warn("WebSocket - 客户端连接出错：session = {}, user = {}, token = {}", session.getId(), this.session.getUserId(), this.session.getCtoken(), error);
	}

	/**
	 * 业务Service
	 *
	 * 说明：WS中无法注入Bean，需要通过ApplicationContext获取
	 */
	private BaseWsService baseWsService;

	/**
	 * 获取/注入Service
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年2月11日
	 */
	private BaseWsService getService() {
		if (baseWsService == null) {
			baseWsService = AppConstant.CONTEXT.getBean(getServiceName(), BaseWsService.class);
		}
		return baseWsService;
	}

	/**
	 * Logger
	 */
	private Logger logger;

	/**
	 * Logger Getter
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年5月18日
	 */
	private Logger getLogger(){
		if (this.logger == null) {
			this.logger = LoggerFactory.getLogger(this.getClass());
		}
		return this.logger;
	}
}